package com.bupt.ilink.controller;


import com.alibaba.fastjson.JSONObject;
import com.bupt.ilink.entity.User;
import com.bupt.ilink.entity.folder.Folder;
import com.bupt.ilink.jwt.JwtProperties;
import com.bupt.ilink.entity.pojo.Response;
import com.bupt.ilink.entity.userManagement.DTO.UserMetaResponse;
import com.bupt.ilink.jwt.InvalidJwtAuthenticationException;
import com.bupt.ilink.jwt.JwtTokenProvider;
import com.bupt.ilink.service.FolderService;
import com.bupt.ilink.service.OssService;
import com.bupt.ilink.service.StudyTreeJsonService;
import com.bupt.ilink.service.impl.UserServiceImpl;
import com.bupt.ilink.utils.*;
import com.volcengine.model.maas.Base;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.net.URLEncoder;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private OssService ossService;

    @Autowired
    JwtProperties jwtProperties;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private UserServiceImpl userDetailsService;

    @Autowired
    private FolderService folderService;

    @Autowired
    private StudyTreeJsonService studyTreeJsonService;

    @Autowired
    private UserServiceImpl userService;

    @Value("${web_url.local_frontend_ip}")
    private String localFrontendIp;

    @Value("${web_url.local_backend_ip}")
    private String localBackendIp;

    @Value("${web_url.bupt_auth}")
    private String buptAuthPrefix;

    @Autowired
    private HttpUtils httpUtils;
    private final KeyPair keyPair = RSAUtils.generateKeyPair();

    public UserController() throws NoSuchAlgorithmException {
    }

    @GetMapping("/publicKey")
    public R getPublicKey() {
        return R.ok("", Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
    }

    @PostMapping("/login")
    public R login(@RequestBody UserRequest request, HttpServletResponse response) {
        String username = request.getUsername();
        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (user == null) {
            return R.failure("Username not found");
        }

        String decryptedPassword = RSAUtils.decrypt(request.getPassword(), keyPair.getPrivate());

        authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, decryptedPassword));

        Map<String, String> accessTokenData = new HashMap<>();
        User new_user = (User) user;
//        accessTokenData.put("sub", new_user.getUserId());
        accessTokenData.put("sub", new_user.getUserId());
        accessTokenData.put("type", "access");
        long accessTokenExpiresIn = jwtProperties.getValidityInMs();
        String accessToken = jwtTokenProvider.createToken(accessTokenData, accessTokenExpiresIn);

        Map<String, String> refreshTokenData = new HashMap<>();
        refreshTokenData.put("sub", new_user.getUserId());
        refreshTokenData.put("type", "refresh");
        long refreshTokenExpiresIn = jwtProperties.getRefreshValidityInMs();
        String refreshToken = jwtTokenProvider.createToken(refreshTokenData, refreshTokenExpiresIn);

        Map<String, Object> tokens = new HashMap<>();
        tokens.put("access_token", accessToken);
        tokens.put("refresh_token", refreshToken);
        tokens.put("token_type", "bearer");

        Cookie accessCookie = new Cookie("access_token_lf", accessToken);
        accessCookie.setPath("/");
        accessCookie.setHttpOnly(false);
        accessCookie.setSecure(false);
        accessCookie.setMaxAge((int)jwtProperties.getValidityInMs());
        response.addCookie(accessCookie);
        Cookie refreshCookie = new Cookie("refresh_token_lf", refreshToken);
        refreshCookie.setPath("/");
        refreshCookie.setHttpOnly(false);
        refreshCookie.setSecure(false);
        refreshCookie.setMaxAge((int)jwtProperties.getRefreshValidityInMs());
        response.addCookie(refreshCookie);

        return R.ok("Login successful", tokens);
    }

    /*
     * 学校统一身份登录
     *
 * @param ticket
     * @return com.bupt.ilink.utils.R
     * @author liuzheng
     * @create 2024-09-10
     **/

    @PostMapping("/school_login")
    public R schoolLogin(@RequestBody UserRequest request, HttpServletResponse response){
        String username = request.getUsername();
        String decryptedPassword = RSAUtils.decrypt(request.getPassword(), keyPair.getPrivate());
        String buptLoginUrl = buptAuthPrefix + "/v1/tickets";
        MultiValueMap<String,Object> params = new LinkedMultiValueMap<>();
        params.add("username",username);
        params.add("password",decryptedPassword);

        //    发送请求到统一身份登录接口
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE));
        try {
            // 得到的是HTML结果，需要解析得到TGT
            String loginPost = httpUtils.post(buptLoginUrl, params, headers, String.class);
            // 解析得到的 TGT 查看是否正确
            // TGT 长期有效，后续可以基于缓存优化登录
            String TGT = loginPost;
            //  利用TGT获取ticket
            String buptGetTicketUrl = buptAuthPrefix + "/v1/tickets/" + TGT;
            params.clear();
            String localBackendUrl = "http://" + localBackendIp;
            params.add("service",localBackendUrl);
            String getTicketPost = httpUtils.post(buptGetTicketUrl, params, headers, String.class);
            log.info("获取得到的 ticket " + getTicketPost);
            //  解析得到tickets 需要判断是否正确
            String ticket = getTicketPost;
            String buptAuthUrl = buptAuthPrefix + "/serviceValidate?service={service}&ticket={ticket}";
            params.clear();
            Map<String,Object> ticketParams = new HashMap<>();
            ticketParams.put("service", localBackendUrl);
            ticketParams.put("ticket",ticket);
            String numberAndTypeString = httpUtils.get(buptAuthUrl, ticketParams, String.class);
            log.info("获取得到的xml" + numberAndTypeString);
            Document document = DocumentHelper.parseText(numberAndTypeString);
            // 获取根节点 cas:serviceResponse
            Element rootElement = document.getRootElement();
            // 解析成功和失败节点
            Element successElement = rootElement.element("authenticationSuccess");
            Element errorElement = rootElement.element("authenticationFailure");

            if (errorElement != null || successElement == null) {
                return R.failure("统一身份登录失败,ticket 错误" + errorElement.getData());
            }

            // 解析XML获取学号，姓名，人员类别
            String name = successElement.element("attributes").element("name").getText();
            String type = successElement.element("attributes").element("type").getText();
            String employeeNumber = successElement.element("attributes").element("employeeNumber").getText();
            if (employeeNumber == null || employeeNumber.isEmpty()) {
                return R.failure("获取身份认证信息失败");
            }
            // 检测账号是否存在，不存在则创建
            // TODO: 密码默认为学号+123， 例如：2021211161+123
            UserDetails user = userDetailsService.loadUserByUsername(employeeNumber);
            if (user == null) {
                String password = employeeNumber + "+123";
                User newUser = new User(employeeNumber, password);
                newUser.setNickname(name);
                newUser.setUserType(type);
                userDetailsService.createUser(newUser);
                Folder folder = new Folder();
                folder.setUserId(newUser.getUserId());
                folderService.createFolder(folder);
                studyTreeJsonService.storeJsonCopiesForUser(newUser.getUserId());

                Map<String, Object> tokens = userService.generateTokens(newUser.getUserId());
                userService.setTokenCookies(response, tokens);

                return R.ok("注册并登录成功", tokens);
            }
            User schoolUser = (User) user;
            Map<String, Object> tokens = userService.generateTokens(schoolUser.getUserId());
            userService.setTokenCookies(response, tokens);
            return R.ok("登录成功", tokens);
        } catch (Exception e) {
            return R.failure("统一身份登录失败" + e.getMessage());
        }
    }
    @PostMapping("/register")
    public R register(@RequestBody UserRequest request) {
        String username = request.getUsername();
        String password = request.getPassword();

        if (userDetailsService.userExists(username)) {
            return R.failure("Username already exists");
        }

        User newUser = new User(username, password);
        userDetailsService.createUser(newUser);
        Folder folder = new Folder();
        folder.setUserId(newUser.getUserId());
        folderService.createFolder(folder);
        studyTreeJsonService.storeJsonCopiesForUser(newUser.getUserId());
        System.out.println("注册时插入技能树副本");
        String id = newUser.getUserId();
        Map<String, Object> data = new HashMap<>();
        data.put("userId", id);
        data.put("username", username);
        return R.ok("User registered successfully", data);
    }

    @PostMapping("/personal_register")
    public R personal_login(@RequestBody UserRequest request){
        String username = request.getUsername();
        String schoolName = request.getSchoolName();
        String nickname = request.getNickname();
        String email = request.getEmail();
        if(schoolName == null || nickname == null){
            return R.failure("Please fill in all the information");
        }
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if(userDetails == null){
            return R.failure("Username not found");
        }
        User user = (User) userDetails;
        user.setSchoolName(schoolName);
        user.setEmail(email);
        user.setNickname(nickname);
//        user.setSchool_id(school_id);
        userDetailsService.updateUser(user);
        String id = user.getUserId();
        Map<String, Object> data = new HashMap<>();
        data.put("userId", id);
        data.put("schoolName", schoolName);
        data.put("nickname", nickname);

        return R.ok("Personal information updated successfully", data);
    }

    @PostMapping("/refresh")
    public R refresh(@CookieValue(value = "refresh_token_lf") String refreshToken, HttpServletResponse response) {
        if (refreshToken == null) {
            return R.failure("No refresh token found");
        }
        try{
            jwtTokenProvider.validateToken(refreshToken);
        } catch (Exception e){
            return R.failure(e.getMessage());
        }
        Map<String, String> accessTokenData = new HashMap<>();
        String userId = jwtTokenProvider.getUserIdFromToken(refreshToken);
        accessTokenData.put("sub", userId);
        accessTokenData.put("type", "access");
        long accessTokenExpiresIn = jwtProperties.getValidityInMs();
        String accessToken = jwtTokenProvider.createToken(accessTokenData, accessTokenExpiresIn);

        Map<String, String> refreshTokenData = new HashMap<>();
        refreshTokenData.put("sub", userId);
        refreshTokenData.put("type", "refresh");
        long refreshTokenExpiresIn = jwtProperties.getRefreshValidityInMs();
        String newRefreshToken = jwtTokenProvider.createToken(refreshTokenData, refreshTokenExpiresIn);

        Map<String, Object> tokens = new HashMap<>();
        tokens.put("access_token", accessToken);
        tokens.put("refresh_token", newRefreshToken);
        tokens.put("token_type", "bearer");

        Cookie accessCookie = new Cookie("access_token_lf", accessToken);
        accessCookie.setPath("/");
        accessCookie.setHttpOnly(false);
        accessCookie.setSecure(false);
        accessCookie.setMaxAge((int)jwtProperties.getValidityInMs());
        response.addCookie(accessCookie);

        Cookie refreshCookie = new Cookie("refresh_token_lf", refreshToken);
        refreshCookie.setPath("/");
        refreshCookie.setHttpOnly(false);
        refreshCookie.setSecure(false);
        refreshCookie.setMaxAge((int)jwtProperties.getRefreshValidityInMs());
        response.addCookie(refreshCookie);
        return R.ok("Token refreshed successfully", tokens);
    }
    //个人资料
    //获取基本个人资料
    @GetMapping("/getUsermeta")// @RequestHeader("Authorization") String token
    public R getUserMeta(@AuthenticationPrincipal UserDetails userDetails) {
        try {
            User user = (User) userDetails;
            UserMetaResponse response =userDetailsService.getUserMetaById(user.getUserId());
            if (response == null) {
                return R.failure("用户未找到");
            }
            return R.ok("用户信息成功召回", response);
        } catch (IllegalArgumentException e) {
            return R.failure("用户信息获取失败",e.getMessage());
        }
    }

    //获取头像封面
//    @GetMapping("/get_avatar")
//    public R getAvatar(@AuthenticationPrincipal UserDetails userDetails) {
//        try {
//            User user = (User) userDetails;
//            String avatarUrl = userDetailsService.getAvatarUrl(user.getUserId());
//            if (avatarUrl == null) {
//                return R.failure("用户未找到");
//            }
//            return R.ok("用户头像成功召回", avatarUrl);
//        } catch (IllegalArgumentException e) {
//            return R.failure("用户信息获取失败",e.getMessage());
//        }
//    }
    //更新用户封面和头像
    @PutMapping("/update_user_image")
    public R updateUsermeta( @AuthenticationPrincipal UserDetails userDetails,
                             @RequestParam(required = false)MultipartFile userCover,@RequestParam(required = false)MultipartFile userImage) {
        User user = (User) userDetails;
        return userDetailsService.updateUserImageById(user,userCover,userImage);

    }


    //写入个人资料
    @PutMapping("/update_usermeta")
    public R updateUsermeta(@RequestBody UserMetaResponse userMetaResponse, @AuthenticationPrincipal UserDetails userDetails) {
        try {
            User user = (User) userDetails;

            boolean isUpdated = userDetailsService.updateUserMetaById(user.getUserId(), userMetaResponse);
            if (isUpdated) {
                return R.ok("写入个人资料成功");
            } else {
                log.error("Failed to update user meta for {}", user.getUserId());


                return R.failure("User not found or update failed");
            }
        } catch (InvalidJwtAuthenticationException e) {
            return R.failure(e.getMessage());
        }
    }

//    @PutMapping("/update_usermeta")
//    public R updateUsermeta(@RequestBody UserMetaResponse userMetaResponse, @AuthenticationPrincipal UserDetails userDetails, @RequestParam(required = false)MultipartFile userCover,@RequestParam(required = false)MultipartFile userImage) {
//        try {
//        User user = (User) userDetails;
//        String Cover_path;
//        String image_path;
//        //不为空时上传封面和用户头像
//        if (userCover != null) {
//            Cover_path=userDetailsService.uploadUserImage(userCover,user.getUserId());
////            if (Cover_path != null) {
////                //上传成功更新数据库
////                userMetaResponse.setUserCover(Cover_path);
////            }
//        }else {
//            Cover_path=null;
//        }
//        if (userImage != null) {
//            image_path=userDetailsService.uploadUserImage(userImage,user.getUserId());
////            if (image_path != null) {
////                //上传成功更新数据库
////                userMetaResponse.setUserImage(image_path);
////            }
//        }else {
//            image_path=null;
//        }
//
//            boolean isUpdated = userDetailsService.updateUserMetaById(user.getUserId(), userMetaResponse,Cover_path,image_path);
//        if (isUpdated) {
//            return R.ok("写入个人资料成功");
//        } else {
//            log.error("Failed to update user meta for {}", user.getUserId());
//            //撤回对图片的导入
//            //待增加
//
//            return R.failure("User not found or update failed");
//        }
//        } catch (InvalidJwtAuthenticationException e) {
//            return R.failure(e.getMessage());
//        }
//    }

    //账号设置
    //修改密码
    @PostMapping("/changepassword")
    public R changePassword(@RequestParam String oldPassword,
                            @RequestParam String newPassword,@AuthenticationPrincipal UserDetails userDetails) {
        try {
            User user = (User) userDetails;
            userDetailsService.changePassword(user.getUserId(), oldPassword, newPassword);
            return R.ok("修改密码成功");
        } catch (IllegalArgumentException e) {
            return R.failure(e.getMessage());
        }
    }
//    @PostMapping("/changepassword")
//    public ResponseEntity<UserResponse<Void>> changePasswordjwt(@RequestHeader("Authorization") String token,
//                                                             @RequestParam String oldPassword,
//                                                             @RequestParam String newPassword) {
//        try {
//            if (token != null && token.startsWith("Bearer ")) {
//                token = token.substring(7);
//            } else {
//                return new ResponseEntity<>(UserResponse.error("Invalid token", "INVALID_TOKEN"), HttpStatus.UNAUTHORIZED);
//            }
//
//            if (jwtTokenProvider.validateToken(token)) {
//                String userId = jwtTokenProvider.getUserid(token);
//                userDetailsService.changePassword(userId, oldPassword, newPassword);
//                return new ResponseEntity<>(UserResponse.success(null), HttpStatus.OK);
//            } else {
//                return new ResponseEntity<>(UserResponse.error("Invalid token", "INVALID_TOKEN"), HttpStatus.UNAUTHORIZED);
//            }
//        } catch (InvalidJwtAuthenticationException e) {
//            return new ResponseEntity<>(UserResponse.error("Invalid token", "INVALID_TOKEN"), HttpStatus.UNAUTHORIZED);
//        } catch (IllegalArgumentException e) {
//            return new ResponseEntity<>(UserResponse.error(e.getMessage(), "CHANGE_PASSWORD_FAILED"), HttpStatus.BAD_REQUEST);
//        }
//    }


    @GetMapping("/whoami")
    public R whoami(@AuthenticationPrincipal UserDetails userDetails){
        User user = (User) userDetails;
        String userId = user.getUserId();
        return R.ok("获取用户id",userId);
    }

}
